#include "kernel.h"
#include <string.h>
#include <stdlib.h>
#include "malloc.h"

/**
 * \file mallocS.c
 * \author Clecio Varjao and Leanne Ross
 * \date October 2007
 * \brief Memory Management
 */

volatile EVENT				Events[MAX_EVENTS];	//!< Array of EVENT objects
volatile QUEUE				Queues[MAX_QUEUE];	//!< Array of QUEUE objects
volatile QUEUE_ITEM			QueueItems[MAX_QUEUE_ITEM];	//!< Array of QUEUE_ITEM objects
volatile TASK_DESCRIPTOR	TDescriptors[MAX_TD];	//!< Array of TASK_DESCRIPTOR objects
volatile TASK_CONSTRUCTOR	TConstructors[MAX_TC];	//!< Array of TASK_CONSTRUCTOR objects
volatile TASK_EXECUTER		TExecuters[MAX_TE];	//!< Array of TASK_EXECUTER objects
volatile int				MUsed[6];	//!< Array with the total of object used by each type

volatile void *NULLPTR=NULL;	//!< NULL pointer (For some reason, when debugging the NULL wasn't pointing to 0
volatile unsigned int ZERO=0;	//!< ZERO (For some reason, when debugging a variable wasn't being set to 0)

/*!
 * Check if an 'object' was sucessefully allocated
 */
void check_alloc(void *o, unsigned char where){
	if (o==NULLPTR){
		OS_Error(101);
	}
}
/*!
 * Return a new EVENT 'object'
 */
EVENT *event_alloc(void){
	volatile unsigned int i1;
	volatile EVENT *ret;
	
	ret=NULLPTR;
	i1=ZERO;

	if (MUsed[0]<MAX_EVENTS){
		for(; i1<MAX_EVENTS; i1++){
			if (Events[i1].initialized!=1){
				ret=(EVENT*)&(Events[i1]);
				memset((void*)ret,0,sizeof(EVENT));
				ret->queue=queue_alloc();
				ret->initialized=1;
				MUsed[0]++;
				break;
			}
		}
	}
	check_alloc((void*)ret, 1);
	return (EVENT*)ret;
}
/*!
 * Release an EVENT 'object'
 */
void event_free(EVENT *e){
	queue_free(e->queue);
	e->initialized=0;
	MUsed[0]--;
}
//	END EVENT


/*!
 * Return a new QUEUE_ITEM 'object'
 */
QUEUE_ITEM *queue_item_alloc(){	
	volatile QUEUE_ITEM *ret;
	unsigned int i;

	ret=NULLPTR;
	i=ZERO;
	if (MUsed[1]<MAX_QUEUE_ITEM){
		for (; i< MAX_QUEUE_ITEM; i++){
			if (QueueItems[i].allocated==0){
				ret=(QUEUE_ITEM*)&QueueItems[i];
				memset((void*)ret,0,sizeof(QUEUE_ITEM));
				ret->allocated=1;
				MUsed[1]++;
				break;
			}
		}
	}
	check_alloc((void*)ret, 2);
	return (QUEUE_ITEM*)ret;
}
/*!
 * Release an QUEUE_ITEM 'object'
 */
void queue_item_free(QUEUE_ITEM *o){
	o->allocated=0;
	MUsed[1]--;
}

/*!
 * Return a new QUEUE 'object'
 */
QUEUE *queue_alloc(){
	unsigned int i;
	volatile QUEUE *ret;

	ret=NULLPTR;
	i=ZERO;
	if (MUsed[2]<MAX_QUEUE){
		for (; i< MAX_QUEUE; i++){
			if (Queues[i].allocated==0){
				ret=(QUEUE*)&Queues[i];
				memset((void*)ret,0,sizeof(QUEUE));
				ret->allocated=1;
				MUsed[2]++;
				break;
			}
		}
	}
	check_alloc((void*)ret, 3);
	return (QUEUE*)ret;
}

/*!
 * Release an QUEUE 'object'
 */
void queue_free(QUEUE *q){
	volatile QUEUE_ITEM *t1, *t2;
	t1=q->next;
	while(t1!=NULLPTR){
		t2=t1->next;
		queue_item_free((QUEUE_ITEM*)t1);
		t1=t2;
	}
	q->allocated=0;
	MUsed[2]--;
}
// END QUEUE

/*!
 * Return a new TASK_CONSTRUCTOR 'object'
 */
TASK_CONSTRUCTOR *TC_alloc(){
	volatile TASK_CONSTRUCTOR *ret;
	volatile unsigned int i;

	ret=NULLPTR;
	i=ZERO;

	if (MUsed[3]<MAX_TC){
		for (; i<MAX_TC; i++){
			if (TConstructors[i].allocated==0){
				ret=(TASK_CONSTRUCTOR*)&TConstructors[i];
				memset((void*)ret,0,sizeof(TASK_CONSTRUCTOR));
				ret->allocated=1;
				MUsed[3]++;
				break;
			}
		}
	}
	check_alloc((void*)ret, 4);
	return (TASK_CONSTRUCTOR*)ret;
}

/*!
 * Release a TASK_CONSTRUCTOR 'object'
 */
void TC_free(TASK_CONSTRUCTOR *o){
	o->allocated=0;
	MUsed[3]--;
}

/*!
 * Return a new TASK_DESCRIPTOR 'object'
 */
TASK_DESCRIPTOR *TD_alloc(){
	volatile TASK_DESCRIPTOR *ret;
	unsigned int i;

	ret=NULLPTR;
	i=ZERO;
	if (MUsed[4]<MAX_TD){
		for (; i<MAX_TD; i++){
			if (TDescriptors[i].allocated==0){
				ret=(TASK_DESCRIPTOR*)&TDescriptors[i];
				memset((void*)ret,0,sizeof(TASK_DESCRIPTOR));
				ret->allocated=1;
				MUsed[4]++;
				break;
			}
		}
	}
	check_alloc((void*)ret, 5);
	return (TASK_DESCRIPTOR*)ret;
}

/*!
 * Release a TASK_DESCRIPTOR 'object'
 */
void TD_free(TASK_DESCRIPTOR *o){
	o->allocated=0;
	MUsed[4]--;	
}

/*!
 * Return a new TASK_EXECUTER 'object'
 */
TASK_EXECUTER *TE_alloc(){
	volatile TASK_EXECUTER *ret;
	unsigned int i;

	ret=NULLPTR;
	i=ZERO;
	if (MUsed[5]<MAX_TE){
		for (; i<MAX_TE; i++){
			if (TExecuters[i].allocated==0){
				ret=(TASK_EXECUTER*)&TExecuters[i];
				memset((void*)ret,0,sizeof(TASK_EXECUTER));
				ret->allocated=1;
				MUsed[5]++;
				break;
			}
		}
	}
	check_alloc((void*)ret, 6);
	return (TASK_EXECUTER*)ret;
}

/*!
 * Release a TASK_EXECUTER 'object'
 */
void TE_free(TASK_EXECUTER *o){
	o->allocated=0;
	MUsed[5]--;
}
